#include "snakes.h"

void SetPos(short x, short y)
{
    HANDLE houtput = NULL;
    houtput = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos = { x,y };
    SetConsoleCursorPosition(houtput, pos);
}

void SetState(int size,  BOOL state)
{
    HANDLE houtput = NULL;
    houtput = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO cursor_info = { 0 };
    GetConsoleCursorInfo(houtput, &cursor_info);
    cursor_info.dwSize = size;
    cursor_info.bVisible = state;
    SetConsoleCursorInfo(houtput, &cursor_info);
}

void WelcomeToGame()
{
    SetPos(40, 14);
    wprintf(L"欢迎来到贪吃蛇小游戏\n");
    SetPos(42, 20);
    system("pause");
    system("cls");
    SetPos(28, 14);
    wprintf(L"用 ↑ ↓ ← → 来控制蛇的移动,按F3加速,F4减速。\n");
    SetPos(28, 15);
    wprintf(L"加速能够获得更多的分数。\n");
    SetPos(42, 20);
    system("pause");
    system("cls");

}
void CreateMap()
{
    //上边框
    for (int i = 0;i < 29;i++)
    {
        wprintf(L"%lc", WALL);
    }
    //下边框
    SetPos(0, 26);
    for (int i = 0;i < 29;i++)
    {
        wprintf(L"%lc", WALL);
    }
    //左边框
    SetPos(0, 1);
    for (int i = 0;i <= 25;i++)
    {
        wprintf(L"%lc\n", WALL);
    }
    //右边框;
    for (int i = 0;i <= 25;i++)
    {
        SetPos(56, i);
        wprintf(L"%lc\n", WALL);
    }
    //getchar();
}

void InitSnake(pSnake ps)
{
    pSnakeNode cur = NULL;
    for (int i = 0;i < 5;i++)
    {
        cur = (pSnakeNode)malloc(sizeof(SnakeNode));
        if (cur == NULL)
        {
            perror("InitSnake()::malloc()");
            return;
        }
        cur->next = NULL;
        cur->x = POS_X + 2 * i;
        cur->y = POS_Y;
        if (ps->_pSnake == NULL)
        {
            ps->_pSnake = cur;
        }
        else
        {
            cur->next = ps->_pSnake;
            ps->_pSnake = cur;
        }
    }
    cur = ps->_pSnake;
    while (cur)
    {
        SetPos(cur->x, cur->y);
        wprintf(L"%lc", BODY);
        cur = cur->next;
    }
    //设置蛇的属性
    ps->_dir = RIGHT;
    ps->_score = 0;
    ps->_food_weight = 10;
    ps->_sleep_time = 200;
    ps->_state = OK;
    //getchar();
}

void CreateFood(pSnake ps)
{
    int x = 0;
    int y = 0;
again:
    do
    {
        x = rand() % 53 + 2;
        y = rand() % 25 + 1;
    } while (x % 2 != 0);
    //食物的坐标不可和蛇重合
    pSnakeNode cur = ps->_pSnake;
    while (cur)
    {
        if (x == cur->x && y == cur->y)
        {
            goto again;
        }
        cur = cur->next;
    }
    //创建食物节点
    pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
    if (pFood == NULL)
    {
        perror("CreateFood()::malloc()");
        return;
    }
    pFood->x = x;
    pFood->y = y;
    pFood->next = NULL;
    SetPos(x, y);
    wprintf(L"%lc", FOOD);
    ps->_pFood = pFood;
}

void pause()
{
    while (1)
    {
        Sleep(200);
        if (KEY_PRESS(VK_SPACE))
        {
            break;
        }
    }
}

int NextIsFood(pSnakeNode pnext, pSnake ps)
{
    return (ps->_pFood->x == pnext->x && ps->_pFood->y == pnext->y);
}

void EatFood(pSnakeNode pnext, pSnake ps)
{
    //头插法
    ps->_pFood->next = ps->_pSnake;
    ps->_pSnake = ps->_pFood;
    //释放下一个位置的节点
    free(pnext);
    pnext = NULL;
    pSnakeNode cur = ps->_pSnake;
    //打印蛇
    while (cur)
    {
        SetPos(cur->x, cur->y);
        wprintf(L"%lc", BODY);
        cur = cur->next;
    }
    ps->_score += ps->_food_weight;
    //重新创建食物
    CreateFood(ps);
}
void NoFood(pSnakeNode pnext, pSnake ps)
{
    //没有遇食物
    pnext->next = ps->_pSnake;
    ps->_pSnake = pnext;

    pSnakeNode cur = ps->_pSnake;
    while (cur->next->next != NULL)
    {
        SetPos(cur->x, cur->y);
        wprintf(L"%lc", BODY);
        cur = cur->next;
    }

    //最后一个节点打印成空格
    SetPos(cur->next->x, cur->next->y);
    printf("  ");
    free(cur->next);
    cur->next = NULL;
}

void KillByWall(pSnake ps)
{
    if (ps->_pSnake->x == 0 || ps->_pSnake->x == 56 || ps->_pSnake->y == 0 || ps->_pSnake->y == 26)
    {
        ps->_state = KILL_BY_WALL;
    }
}
void KillBySelf(pSnake ps)
{
    pSnakeNode cur = ps->_pSnake->next;
    while (cur)
    {
        if (cur->x == ps->_pSnake->x && cur->y == ps->_pSnake->y)
        {
            ps->_state = KILL_BY_SELF;
            break;
        }
        cur = cur->next;
    }
}

void SnakeMove(pSnake ps)
{
    //创建一个节点表示即将到的下一个节点
    pSnakeNode pNext = (pSnakeNode)malloc(sizeof(SnakeNode));
    if (pNext == NULL)
    {
        perror("SnakeMove()::malloc");
        return;
    }
    switch (ps->_dir)
    {
        case UP:
            pNext->x = ps->_pSnake->x;
            pNext->y = ps->_pSnake->y - 1;
            break;
        case DOWN:
            pNext->x = ps->_pSnake->x;
            pNext->y = ps->_pSnake->y + 1;
            break;
        case LEFT:
            pNext->x = ps->_pSnake->x - 2;
            pNext->y = ps->_pSnake->y;
            break;
        case RIGHT:
            pNext->x = ps->_pSnake->x + 2;
            pNext->y = ps->_pSnake->y;
            break;
    }
    if (NextIsFood(pNext, ps))
    {
        EatFood(pNext, ps);
    }
    else
    {
        NoFood(pNext, ps);
    }
}

void PrintHelpInfo()
{
    SetPos(64, 12);
    wprintf(L"%ls", L"不能穿墙，不能咬到自己。");
    SetPos(64, 14);
    wprintf(L"%ls", L"用 ↑ ↓ ← → 来控制蛇的移动。");
    SetPos(64, 16);
    wprintf(L"%ls", L"按F3加速,F4减速");
    SetPos(64, 18);
    wprintf(L"%ls", L"按ESC退出游戏,按空格暂停游戏。");
    SetPos(64, 20);
    wprintf(L"%ls", L"Snake Game");

}

void GameRun(pSnake ps)
{
    PrintHelpInfo();
    do
    {
        /* code */
        //打印总分数和食物的分值
        SetPos(64, 9);
        wprintf(L"总分数: %5d\n", ps->_score);
        SetPos(64, 10);
        wprintf(L"当前食物得分分数: %5d\n", ps->_food_weight);
        
        if (KEY_PRESS(VK_UP) && ps->_dir != DOWN)
        {
            ps->_dir = UP;
        }
        else if (KEY_PRESS(VK_DOWN) && ps->_dir != UP)
        {
            ps->_dir = DOWN;
        }
        else if (KEY_PRESS(VK_LEFT) && ps->_dir != RIGHT)
        {
            ps->_dir = LEFT;
        }
        else if (KEY_PRESS(VK_RIGHT) && ps->_dir != LEFT)
        {
            ps->_dir = RIGHT;
        }
        else if (KEY_PRESS(VK_ESCAPE))
        {
            //退出游戏
            ps->_state = END_NORMAL;
        }
        else if (KEY_PRESS(VK_SPACE))
        {
            pause();
        }
        else if (KEY_PRESS(VK_F3))
        {
            if (ps->_sleep_time > 80)
            {
                ps->_sleep_time -= 30;
                ps->_food_weight += 2;
            }
        }
        else if (KEY_PRESS(VK_F4))
        {
            if(ps->_food_weight > 2 )
            {
                ps->_food_weight -= 2;
                ps->_sleep_time += 30;
            }
        }
        SnakeMove(ps);
        KillByWall(ps);
        KillBySelf(ps);
        Sleep(ps->_sleep_time);
    } while (ps->_state == OK);
}


void GameEnd(pSnake ps)
{
    SetPos(24, 12);
    switch (ps->_state)
    {
    case END_NORMAL:
        printf("您主动结束游戏。\n");
        break;
    case KILL_BY_SELF:
        printf("您撞到了自己，游戏结束。");
        break;
    case KILL_BY_WALL:
        printf("您撞到了墙，游戏结束。");
        break;
    }
    //释放蛇身节点
    pSnakeNode cur = ps->_pSnake;
    while (cur)
    {
        pSnakeNode del = cur;
        cur = cur->next;
        free(del);
    }
    Sleep(800);
    system("cls");
}
void GameStart(pSnake ps)
{
    //每次游戏开始前清理屏幕信息
    system("cls");
    //游戏初始化
    system("title 贪吃蛇");
    system("mode con cols=100 lines=30");
    // 0.光标隐藏
    SetState(100, false);
    // 1.打印环境界面
    // 2.功能介绍
    WelcomeToGame();
    // 3.绘制地图
    CreateMap();
    // 4.创建蛇
    InitSnake(ps);
    // 5.创建食物,6.设置游戏相关信息
    CreateFood(ps);
}